/*
 * Created on 11/Abr/2004
 *
 * To change the template for this generated file go to
 * Window&gt;Preferences&gt;Java&gt;Code Generation&gt;Code and Comments
 */
package org.cyborgas.xmltool.tabsheets;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.StringReader;
import java.net.URI;
import java.util.prefs.Preferences;

import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamSource;

import org.cyborgas.swt.RecentFileList;
import org.cyborgas.xmltool.MainWindow;
import org.cyborgas.xmltool.Util;
import org.cyborgas.xmltool.XsltOutpoutProfile;
import org.cyborgas.xmltool.actions.XslOpenAction;
import org.cyborgas.xmltool.actions.XslSaveAction;
import org.cyborgas.xmltool.actions.XslSaveOutputAsAction;
import org.cyborgas.xmltool.actions.XslTransformAction;
import org.dom4j.Document;
import org.dom4j.io.DocumentResult;
import org.dom4j.io.DocumentSource;
import org.dom4j.io.HTMLWriter;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.XMLWriter;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.swt.SWT;
import org.eclipse.swt.browser.Browser;
import org.eclipse.swt.custom.SashForm;
import org.eclipse.swt.custom.StyledText;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.TabFolder;
import org.eclipse.swt.widgets.TabItem;
import org.eclipse.swt.widgets.Text;


/**
 * @author rino
 *
 * To change the template for this generated type comment go to
 * Window&gt;Preferences&gt;Java&gt;Code Generation&gt;Code and Comments
 */
public class XslTransformTab {
	
	private static final String PREF_NODE = "xslt";
	private static final String PREF_OUTPUT_NODE = "xsl output";

	private MainWindow mainWindow;
//	private Document xslDocument = null;
	public URI xslFile = null; 
	public File outputFile = null;
		
	// controls
	private StyledText xslText;
	private TabFolder outputTabFolder;
	private Text outputText;
	private Browser outputWebBrowser;
	private RecentFileList mru;

	public XslTransformTab(MainWindow window) {
		this.mainWindow = window;
	}

	public Composite createControls(Composite parent) {
		GridData gridData;
		
		// containers start
		SashForm mainPane = new SashForm(parent, SWT.VERTICAL);
		
		Composite topPane = new Composite(mainPane, SWT.NULL);
		GridLayout gridLayout = new GridLayout();
		gridLayout.marginWidth = 0;
		topPane.setLayout(gridLayout);

		Composite bottomPane = new Composite(mainPane, SWT.NONE);
		bottomPane.setLayout(new FillLayout());
		outputTabFolder = new TabFolder(bottomPane, SWT.NONE);
		TabItem simpleTabItem = new TabItem(outputTabFolder, SWT.NONE);
		simpleTabItem.setText("Output");
		TabItem browserTabItem = new TabItem(outputTabFolder, SWT.NONE);
		browserTabItem.setText("Browser");

		// containers end

		// controls start
		Label xslLabel = new Label(topPane, SWT.NONE);
		xslLabel.setText("XSL &Stylesheet");
		gridData = new GridData();
		gridData.verticalAlignment = GridData.FILL;
		gridData.grabExcessHorizontalSpace = true;
		xslLabel.setLayoutData(gridData);

		xslText =
			new StyledText(
				topPane,
				SWT.MULTI | SWT.BORDER | SWT.V_SCROLL | SWT.H_SCROLL);
		gridData = new GridData();
		gridData.horizontalAlignment = GridData.FILL;
		gridData.verticalAlignment = GridData.FILL;
		gridData.grabExcessHorizontalSpace = true;
		gridData.grabExcessVerticalSpace = true;
		xslText.setLayoutData(gridData);
		
		outputText =
			new Text(
				outputTabFolder,
				SWT.BORDER
					| SWT.MULTI
					| SWT.V_SCROLL
					| SWT.H_SCROLL
					| SWT.READ_ONLY);
		simpleTabItem.setControl(outputText);

		outputWebBrowser = new Browser(outputTabFolder, SWT.BORDER);
		outputWebBrowser.setUrl("about:blank");
		browserTabItem.setControl(outputWebBrowser);
					
		// controls end


		return mainPane;
	}
	
	public MenuManager createMenu() {
		MenuManager menu = new MenuManager("&XSLT");
		menu.add(new XslOpenAction(mainWindow, this));
		menu.add(new XslSaveAction(mainWindow, this));
		mru = new RecentFileList(menu, Util.preferences.node(PREF_NODE));
		menu.add(new Separator());
		menu.add(new XslTransformAction(mainWindow, this));
		menu.add(new XslSaveOutputAsAction(mainWindow, this));

		mru.addListener(new Listener() {
			public void handleEvent(Event event) {
				load((URI) event.data);
			}
		});

		return menu;
	}

	/**
	 * @param file
	 */
	public void load(URI url) {
		try {
			String text = Util.readFile(url);			
			xslText.setText(text);			
//			Document xslDocument = new SAXReader().read(file);
//			xslText.setText(xslDocument.asXML());
			mru.add(url);
			this.xslFile = url;
		} catch (Exception e) {
			MessageDialog.openError(mainWindow.getShell(), "Error loading URL",
					"The url specified (" + url + ") couldn't be loaded. "
					+ "Reason: 	\n\n" + e.getMessage());
			mru.remove(url);
		}
		mainWindow.tabFolder.setSelection(MainWindow.XSL_TRANSFORM_TAB);
	}

	/**
	 * @param file
	 */
	public void save(URI url) {
		try {
			File file;
			file = new File(url);
			Util.saveFile(file, xslText.getText());
			this.xslFile = url;		
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}

	

	/**
	 * 
	 */
	public void transform() {
		// load the XSL transformer using JAXP
		TransformerFactory factory = TransformerFactory.newInstance();
		Transformer transformer = null;
		try {
			transformer = factory.newTransformer( 
					new StreamSource(new StringReader(xslText.getText())));
		} catch (TransformerConfigurationException e) {
			MessageDialog.openError(mainWindow.getShell(), "Error creating XSL transformer", 
			e.getMessage());
			return;
		}

		// apply the XSL
		if (mainWindow.xmlDocument == null) {
			MessageDialog.openError(
				mainWindow.getShell(),
				"Error applying XSL",
				"Source XML document wasn't loaded.");
			return;
		}
		DocumentSource source = new DocumentSource(mainWindow.xmlDocument.getDocument());
		DocumentResult result = new DocumentResult();
		try {
			transformer.transform(source, result);
		} catch (TransformerException e) {
			MessageDialog.openError(
				mainWindow.getShell(),
				"Error applying XSL",
				"The following error was found while applying XSL: \n\n"
					+ e.getMessage());
			return;
		}

		XsltOutpoutProfile profile = getProfile();

		// get the output
		Document outputDocument = result.getDocument();
		try {
			saveDocument(profile, outputDocument);
			outputText.setText(Util.readFile(this.outputFile));		
			outputWebBrowser.setUrl(this.outputFile.getAbsolutePath());
			mainWindow.tabFolder.setSelection(MainWindow.XSL_TRANSFORM_TAB);
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}

	private XsltOutpoutProfile getProfile() {
		Preferences prefs = Util.preferences.node(PREF_NODE).node(PREF_OUTPUT_NODE);
		String PREFS_PROFILE = "xslt output profile";
		String profileName = prefs.get(PREFS_PROFILE, "html");
		XsltOutpoutProfile profile = (XsltOutpoutProfile) Util.getXsltOutpoutProfile(profileName);
		return profile;
	}

	private void saveDocument(XsltOutpoutProfile profile, Document outputDocument) throws IOException {
		File file = this.outputFile;
		if (file == null) {
			file = File.createTempFile("xmltool", profile.suffix);
			file.deleteOnExit();
		}
		OutputStreamWriter fileWriter;
		if (profile.encoding == null) {
			fileWriter = new OutputStreamWriter(new FileOutputStream(file));
		} else {
			fileWriter = new OutputStreamWriter(new FileOutputStream(file), profile.encoding);
		}
			

		OutputFormat format = null;
		switch (profile.format) {
			case XsltOutpoutProfile.FORMAT_COMPACT:
				format = OutputFormat.createCompactFormat();
				break;
			case XsltOutpoutProfile.FORMAT_PRETTY_PRINT:
				format = OutputFormat.createPrettyPrint();
				break;
		} 
		format.setEncoding(profile.encoding);
		format.setXHTML(profile.xhtml);
		format.setExpandEmptyElements(profile.expandEmptyElements);

		XMLWriter writer = null;
		switch (profile.writer) {
			case XsltOutpoutProfile.WRITER_XML:
				writer = new XMLWriter(fileWriter, format);
				break;
			case XsltOutpoutProfile.WRITER_HTML:
				writer = new HTMLWriter(fileWriter, format);
				break;
		} 
		
		writer.write(outputDocument);
		writer.close();
		fileWriter.close();

		this.outputFile = file;
		
	}



	public void dispose() {
		if (outputWebBrowser != null) {
			outputWebBrowser.dispose();
		} 
		outputWebBrowser = null;
		this.mru.dispose();
	}


}
